package cn.chiship.framework.third.biz.wxpub.controller;

import cn.chiship.framework.common.annotation.SystemOptionAnnotation;
import cn.chiship.framework.common.constants.CommonConstants;
import cn.chiship.framework.third.biz.all.entity.ThirdApplicationKeyConfig;
import cn.chiship.framework.third.biz.all.service.ThirdCacheService;
import cn.chiship.framework.third.biz.wxpub.service.WeixinService;
import cn.chiship.framework.third.core.common.WechatUtils;
import cn.chiship.framework.third.core.properties.ThirdProperties;
import cn.chiship.sdk.core.annotation.NoParamsSign;
import cn.chiship.sdk.core.annotation.NoVerificationAppIdAndKey;
import cn.chiship.sdk.core.annotation.NoVerificationProjectId;
import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.util.OutUtil;
import cn.chiship.sdk.core.util.StringUtil;
import cn.chiship.sdk.core.util.UrlUtil;
import cn.chiship.sdk.third.wx.core.util.WxPubMessageToXml;
import cn.chiship.sdk.third.wx.core.util.WxPubUtil;
import cn.chiship.sdk.third.wx.network.WxPubServicesUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lijian
 */
@Controller
@RequestMapping("/wxPub/auth")
@NoParamsSign
@NoVerificationAppIdAndKey
@NoVerificationProjectId
@Api(tags = "微信交互控制器")
public class WeiXinController {
    private static final Logger LOGGER = LoggerFactory.getLogger(WeiXinController.class);

    @Resource
    private ThirdProperties thirdProperties;
    @Resource
    private WeixinService weixinService;
    @Resource
    private ThirdCacheService cacheService;

    /**
     * 校验
     *
     * @param request
     * @param response
     * @throws
     */
    @ApiOperation(value = "微信校验")
    @GetMapping(produces = "application/json;charset=UTF-8", path = "/{appId}")
    public void valid(
            HttpServletRequest request,
            HttpServletResponse response,
            @PathVariable(value = "appId") String appId) {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echoStr = request.getParameter("echostr");
        try {
            ThirdApplicationKeyConfig applicationKeyConfig = cacheService.getConfigByAppId(appId);
            if (applicationKeyConfig == null) {
                WechatUtils.printlnStr(response, "校验失败");
                LOGGER.error("appId错误，不存在Redis或数据库");
                return;
            }
            String token = applicationKeyConfig.getServerToken();
            if (WxPubUtil.checkSignature(token, signature, timestamp, nonce)) {
                WechatUtils.printlnStr(response, echoStr);
            } else {
                WechatUtils.printlnStr(response, "校验失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            WechatUtils.printlnStr(response, "校验失败");
        }
    }

    /**
     * 处理微信与微信用户通信
     *
     * @param request
     * @param response
     * @throws IOException
     * @throws DocumentException
     */
    @ApiOperation(value = "处理微信与微信用户通信")
    @PostMapping(produces = "application/xml;charset=UTF-8", path = "/{appId}")
    public void dispose(
            HttpServletRequest request,
            HttpServletResponse response,
            @PathVariable(value = "appId") String appId) throws IOException, DocumentException {
        response.setCharacterEncoding("UTF-8");
        ThirdApplicationKeyConfig applicationKeyConfig = cacheService.getConfigByAppId(appId);
        if (applicationKeyConfig == null) {
            WechatUtils.printlnStr(response, "校验失败");
            LOGGER.error("appId错误，不存在Redis或数据库");
            return;
        }

        Map<String, String> map = WxPubMessageToXml.xmlToMap(request.getInputStream());
        String appKey = applicationKeyConfig.getAppId();
        String appSecret = applicationKeyConfig.getAppSecret();
        map.put("appKey", appKey);
        map.put("appSecret", appSecret);
        LOGGER.info("接收到的参数:{}", JSON.toJSON(map));

        WechatUtils.printlnStr(response, weixinService.analysisMessage(map));
    }


    @GetMapping("/login")
    public String login(Model model) {
        return "h5/login";
    }

    @ApiOperation(value = "授权登录回调")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "callback", value = "回调地址", dataTypeClass = String.class, paramType = "query", required = true)
    })
    @GetMapping("/wxAuth")
    public void wxAuth(HttpServletResponse response,
                       @RequestParam(value = "callback") String callback) throws Exception {
        LOGGER.info("接收到的callback:{}", callback);
        try {
            //若appID及appSecret读取数据库或常量值，可在重定向参数携带
            //String redirectUri = thirdProperties.getWxPubAuthRedirectUrl() + "?appId=" + constantsProperties.getWechatAppId() + "&appSecret=" + constantsProperties.getWechatAppSecret() ;
            String redirectUri = thirdProperties.getWxPubAuthRedirectUrl();

            LOGGER.info("redirectUri:{}", redirectUri);
            //WeiXinPubConfig weiXinPubConfig=new WeiXinPubConfig(constantsProperties.getWechatAppId(), constantsProperties.getWechatAppSecret());
            String url = WxPubServicesUtil.getInstance().config().token().getConnectOauth2Url(redirectUri, callback, false);
            LOGGER.info("url:{}", url);
            response.sendRedirect(url);
        } catch (Exception e) {
            e.printStackTrace();
            OutUtil.writeJson(response, BaseResult.error("请检查参数callback"));

        }
    }

    @ApiIgnore
    @GetMapping(value = "/redirectUri")
    public ModelAndView redirectUri(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String code = request.getParameter("code");
        //若上步构建重定向路径携带appid及appsecret，可从参数获得
        WxPubServicesUtil weiXinPubServicesUtils = WxPubServicesUtil.getInstance().config().token();
        BaseResult baseResult = weiXinPubServicesUtils.oauth2AccessToken(code);
        Map query = Maps.newHashMapWithExpectedSize(7);
        if (baseResult.isSuccess()) {
            JSONObject oauth2AccessTokenJson = (JSONObject) baseResult.getData();
            baseResult = weiXinPubServicesUtils.getAccessUserInfo(
                    oauth2AccessTokenJson.getString("access_token"),
                    oauth2AccessTokenJson.getString("openid"));
            if (baseResult.isSuccess()) {
                JSONObject userInfoJson = (JSONObject) baseResult.getData();
                LOGGER.info("userInfo:{}", userInfoJson);
            }
            query.put("openId", oauth2AccessTokenJson.getString("openid"));
        }
        query.put("success", String.valueOf(baseResult.isSuccess()));
        String redirectUrl = UrlUtil.buildUrl(request.getParameter("state"), query);
        LOGGER.info("redirectUrl:{}", redirectUrl);
        return new ModelAndView(new RedirectView(redirectUrl));
    }

}
